#include "unp.h"

#define read_lock(fd,offset,whence,len)   \
        flock_reg(fd,F_SETLK,F_RDLCK,offset,whence,len)

#define readw_lock(fd,offset,whence,len)  \
        flock_reg(fd,F_SETLKW,F_RDLCK,offset,whence,len);

#define write_lock(fd,offset,whence,len)  \
        flock_reg(fd,F_SETLK,F_WRLCK,offset,whence,len);

#define writew_lock(fd,offset,whence,len)  \
        flock_reg(fd,F_SETLKW,F_WRLCK,offset,whence,len);

#define is_write_lockable(fd,offset,whence,len)  \
        flock_test(fd,F_WRLCK,offset,whence,len);

#define is_read_lockable(fd,offset,whence,len)  \
        flock_test(fd,F_RDLCK,offset,whence,len);

#define unlock(fd,offset,whence,len) \
        flock_reg(fd,F_SETLK,F_UNLCK,offset,whence,len)




int flock_reg(int fd,int cmd,int type,off_t offset,int whence,off_t len)
{
  struct flock lock;
  lock.l_type = type;
  lock.l_whence = whence;
  lock.l_start = offset;
  lock.l_len  = len;
  return (fcntl(fd,cmd,&lock));
}

int flock_test(int fd,int type,off_t offset,int whence,off_t len)
{
  struct flock lock;
  lock.l_type = type;
  lock.l_whence = whence;
  lock.l_start = offset;
  lock.l_len = len;
   
  if(fcntl(fd,F_GETLK,&lock) == -1) 
  {
     err_sys("fcntl F_GETLK error");
     return (-1);
  }

  if(lock.l_type == F_UNLCK)
    return 0;

  return lock.l_pid;
}

void increase(int fd){
  char line[1024];
  int  n,seq;
  writew_lock(fd,0,SEEK_SET,0);
  lseek(fd,0L,SEEK_SET);
  n = read(fd,line,1024); 
  line[n]='\0';
  n = sscanf(line,"%d\n",&seq);
  printf(" pid= %ld , seq#=%d\n",(long)getpid(),seq);
  seq++;
  snprintf(line,sizeof(line),"%d\n",seq);
  lseek(fd,0L,SEEK_SET);
  write(fd,line,strlen(line));
  unlock(fd,0,SEEK_SET,0);
}


int main(int argc ,char *argv[])
{

   int fd,cnt,i;
  
   fd = open("./test.dat",O_RDWR|O_CREAT|O_EXCL,FILE_MODE);
   if(fd < 0){
      if(errno != EEXIST)
         err_sys("open error");
      else{
         err_ret("file exists");
         fd = open("./test.dat",O_RDWR,FILE_MODE);
      }
   }
   
   cnt = atoi(argv[1]); 
   for(i=0;i<cnt;i++){
     increase(fd);
   }
   return 0;
}
